---
title: API de Adaptadores do Astro
i18nReady: true
---
import Since from '~/components/Since.astro';
import { FileTree } from '@astrojs/starlight/components';

Astro foi projetado para ser fácil realizar deploy em qualquer provedor da nuvem para SSR (renderização no lado do servidor). Essa habilidade é providenciada por __adaptadores__, que são [integrações](/pt-br/reference/integrations-reference/). Veja o [guia de SSR](/pt-br/guides/server-side-rendering/) para aprender como utilizar um adaptador existente.

## O que é um adaptador

Um adaptador é um tipo especial de [integração](/pt-br/reference/integrations-reference/) que providencia um ponto de entrada para a renderização no lado do servidor. Um adaptador faz duas coisas:

- Implementa APIs específicas de uma hospedagem para lidar com requisições.
- Configura a construção final de acordo com as convenções da hospedagem.

## Construindo um Adaptador

Um adaptador é uma [integração](/pt-br/reference/integrations-reference/) e pode fazer tudo que uma integração pode.

Um adaptador __deve__ chamar a API `setAdapter` no hook `astro:config:done` assim:

```js title="meu-adaptador.mjs"
export default function createIntegration() {
  return {
    name: '@matthewp/meu-adaptador',
    hooks: {
      'astro:config:done': ({ setAdapter }) => {
        setAdapter({
          serverEntrypoint: '@matthewp/meu-adaptador/server.js',
          supportedAstroFeatures: {
              staticOutput: 'stable'
          }  
        });
      },
    },
  };
}
```

O objeto passado para `setAdapter` é definido como:

```ts
interface AstroAdapter {
	name: string;
	serverEntrypoint?: string;
	exports?: string[];
  adapterFeatures: AstroAdapterFeatures;
  supportedAstroFeatures: AstroFeatureMap;
}

export interface AstroAdapterFeatures {
	/**
	 * Cria uma função na edge que irá se comunicar com o middleware do Astro.
	 */
	edgeMiddleware: boolean;
	/**
	 * SSR apenas. Cada rota se torna sua própria função/arquivo.
	 */
	functionPerRoute: boolean;
}

export type SupportsKind = 'unsupported' | 'stable' | 'experimental' | 'deprecated';

export type AstroFeatureMap = {
  /**
   * O adaptador é capaz de servir páginas estáticas
   */
  staticOutput?: SupportsKind;
  /**
   * O adaptador é capaz de servir páginas que são estáticas ou renderizadas pelo servidor
   */
  hybridOutput?: SupportsKind;
  /**
   * O adaptador é capaz de servir páginas SSR
   */
  serverOutput?: SupportsKind;
  /**
   * O adaptador pode emitir assets estáticos
   */
  assets?: AstroAssetsFeature;
};

export interface AstroAssetsFeature {
  supportKind?: SupportsKind;
  /**
   * Define se o adaptador faz deploy de arquivos em um ambiente que é compatível com a biblioteca `sharp`
   */
  isSharpCompatible?: boolean;
  /**
   * Define se o adaptador faz deploy de arquivos em um ambiente que é compatível com a biblioteca `squoosh`
   */
  isSquooshCompatible?: boolean;
}
```

As propriedades são:

* __name__: Um nome único para seu adaptador, usado em logs.
* __serverEntrypoint__: O ponto de entrada para renderização no lado do servidor.
* __exports__: Um array de exportações nomeadas quando utilizado em conjunto com `createExports` (explicado abaixo).
* __adapterFeatures__: Um objeto que habilita funcionalidades específicas que devem ser suportadas pelo adaptador. 
  Essas funcionalidades irão mudar o resultado da build, e o adaptador deve implementar a lógica adequada para lidar com esse resultado diferente. 
* __supportedAstroFeatures__: Um mapa das funcionalidades integradas do Astro. Isso permite o Astro determinar quais funcionalidades um adaptador é incapaz ou não quer suportar para que as mensagens de erro apropriadas sejam fornecidas.

### Ponto de Entrada do Servidor

A API de adaptadores do Astro tenta trabalhar com qualquer tipo de hospedagem e dá uma forma flexível de se adequar com as APIs da hospedagem.

#### Exportações

Algumas hospedagens serverless esperam que você exporte uma função, como `handler`:

```js
export function handler(evento, contexto) {
  // ...
}
```

Com a API de adaptadores você alcança isso implementando `createExports` em seu `serverEntrypoint`:

```js
import { App } from 'astro/app';

export function createExports(manifesto) {
  const app = new App(manifesto);

  const handler = (evento, contexto) => {
    // ...
  };

  return { handler };
}
```

E então em sua integração, quando você chamar `setAdapter`, providencie o nome em `exports`:

```js title="meu-adaptador.mjs" ins={9}
export default function createIntegration() {
  return {
    name: '@matthewp/meu-adaptador',
    hooks: {
      'astro:config:done': ({ setAdapter }) => {
        setAdapter({
          name: '@matthewp/meu-adaptador',
          serverEntrypoint: '@matthewp/meu-adaptador/server.js',
          exports: ['handler'],
        });
      },
    },
  };
}
```

#### Iniciar

Algumas hospedagens esperam que você **inicie** o servidor por si mesmo, por exemplo, observando uma porta. Para esses tipos de hospedagens, a API de adaptadores permite que você exporte uma função `start` que será chamado quando o script de construção é executado.

```js
import { App } from 'astro/app';

export function start(manifesto) {
  const app = new App(manifesto);

  addEventListener('fetch', evento => {
    // ...
  });
}
```

#### `astro/app`

Este módulo é utilizado para renderizar páginas que foram pré-construídas através de `astro build`. Astro utiliza os objetos padrões [Request](https://developer.mozilla.org/pt-BR/docs/Web/API/Request) e [Response](https://developer.mozilla.org/pt-BR/docs/Web/API/Response). Hospedagens que têm uma API diferente para requisições/respostas devem ser convertidos para estes tipos em seus adaptadores.

```js
import { App } from 'astro/app';
import http from 'http';

export function start(manifesto) {
  const app = new App(manifesto);

  addEventListener('fetch', evento => {
    evento.respondWith(
      app.render(evento.request)
    );
  });
}
```

Os métodos a seguir são fornecidos:

##### `app.render(requisicao, { routeData, locals })`

Este método chama a página Astro que corresponde a requisição, a renderiza e retorna uma Promise a um objeto [Response](https://developer.mozilla.org/pt-BR/docs/Web/API/Response). Isso também funciona para rotas de API que não renderizam páginas.

```js
const resposta = await app.render(requisicao);
```

O método aceita um argumento `requisicao` obrigatório e um argumento opcional para [`routeData`](/pt-br/reference/integrations-reference/#referência-do-tipo-routedata) e [`locals`](/pt-br/reference/api-reference/#astrolocals).

Forneça um valor para `routeData` se você já sabe a rota para renderizar. Fazendo isso vai ignorar a chamada interna para [`app.match`](#appmatchrequisicao) para determinar a rota para renderizar.

O exemplo abaixo lê o cabeçalho chamado `x-cabecalho-privado`, tenta analisá-lo como um objeto e passa isso para `locals`, que pode então ser passado para qualquer [função middleware](/pt-br/guides/middleware/).

```js
const cabecalhoPrivado = request.headers.get("x-cabecalho-privado");
let locals = {};
try {
    if (cabecalhoPrivado) {
        locals = JSON.parse(cabecalhoPrivado);
    }
} finally {
    const response = await app.render(request, { locals });
}
```

##### `app.match(requisicao)`

Este método é utilizado para determinar se uma requisição é correspondida pelas regras de roteamento da aplicação Astro.

```js
if(app.match(requisicao)) {
  const resposta = await app.render(requisicao);
}
```

Você geralmente pode chamar `app.render(requisicao)` sem utilizar `.match` pois Astro lida com 404s se você providenciar um arquivo `404.astro`. Utilize `app.match(requisicao)` se você quiser lidar com 404s de forma diferente.

## Permitindo instalação via `astro add`

[O comando `astro add`](/pt-br/reference/cli-reference/#astro-add) permite que usuários facilmente adicionem integrações e adaptadores em seus projetos. Se você quiser que _seu_ adaptador seja instalável com essa ferramenta, **adicione `astro-adapter` no campo `keywords` do seu `package.json`**:

```json
{
  "name": "exemplo",
  "keywords": ["astro-adapter"],
}
```

Assim que você [publicar seu adaptador no npm](https://docs.npmjs.com/cli/v8/commands/npm-publish), executar `astro add exemplo` irá instalar seu pacote com quaisquer dependências de pares especificadas em seu `package.json`. Nós também iremos instruir usuários a atualizarem a configuração de seus projetos manualmente.

## Funcionalidades do Astro

<Since v="3.0.0" />

Funcionalidades do Astro é uma forma para que adaptadores digam ao Astro se eles são ou não capazes de suportar uma funcionalidade, e também o nível de suporte do adaptador.  

Ao utilizar essas propriedades, Astro irá:
- executar validação específica; 
- emitir contextos para os registros;

Essas operações são executadas com base nas funcionalidades suportadas ou não, seu nível de suporte, e a configuração que o usuário utiliza.

A configuração a seguir diz ao Astro que esse adaptador tem suporte experimental para assets, porém o adaptador não é compatível com os serviços Sharp e Squoosh integrados:

```js title="meu-adaptador.mjs" ins={9-15}
export default function createIntegration() {
  return {
    name: '@matthewp/meu-adaptador',
    hooks: {
      'astro:config:done': ({ setAdapter }) => {
        setAdapter({
          name: '@matthewp/meu-adaptador',
          serverEntrypoint: '@matthewp/meu-adaptador/server.js',
          supportedAstroFeatures: {
            assets: {
              supportKind: "experimental",
              isSharpCompatible: false,
              isSquooshCompatible: false
            }
          }  
        });
      },
    },
  };
}
```

Astro irá registar um **aviso** ao terminal:

```
[@matthewp/meu-adaptador] A funcionalidade é experimental e sujeita a problemas ou mudanças.
```

e um erro se o serviço usado para assets não é compatível com o adaptador:

```
[@matthewp/meu-adaptador] O adaptador atualmente selecionado `@matthewp/meu-adaptador` não é compatível com o serviço "Sharp". Seu projeto não será capaz de build.
```

## Funcionalides do Adaptador

Um conjunto de funcionalidades que modificam o resultado dos arquivos emitidos. Quando um adaptador opta por essas funcionalidades, ele irá adquirir informação adicional dentro de hooks específicos.

### `functionPerRoute`

Essa é uma funcionalidade que é habilitada ao utilizar SSR apenas. Por padrão, Astro emite um único arquivo `entry.mjs`, que é responsável por emitir a página renderizada a cada requisição.

Quando `functionPerRoute` é `true`, Astro irá ao invés disso criar um arquivo separado para cada rota definida no projeto.

Cada arquivo emitido irá apenas renderizar uma página. As páginas serão emitidas dentro do diretório `dist/pages/` (ou dentro de um diretório `/pages/` no diretório especificado para [`outDir`](/pt-br/reference/configuration-reference/#outdir)), e os arquivos emitidos irão manter o mesmo caminho de arquivo que o diretório `src/pages/`.

Os arquivos dentro do diretório `pages/` da build refletirão a estrutura do diretório dos seus arquivos de página em `src/pages/`, por exemplo:

<FileTree>
- dist/
    - pages/
        - blog/
            - entry.\_slug\_.astro.mjs
            - entry.sobre.astro.mjs
        - entry.index.astro.mjs
</FileTree>

Habilite essa funcionalidade passando `true` ao adaptador.

```js title="meu-adaptador.mjs" ins={9-11}
export default function createIntegration() {
  return {
    name: '@matthewp/meu-adaptador',
    hooks: {
      'astro:config:done': ({ setAdapter }) => {
        setAdapter({
          name: '@matthewp/meu-adaptador',
          serverEntrypoint: '@matthewp/meu-adaptador/server.js',
          adapterFeatures: {
              functionPerRoute: true
          } 
        });
      },
    },
  };
}
```

Então, consuma o hook [`astro:build:ssr`](/pt-br/reference/integrations-reference/#astrobuildssr), que irá te dar um objeto `entryPoints` que mapeia uma rota de página ao arquivo físico emitido após a build.

```js title="meu-adaptador.mjs" ins={15-19}
export default function createIntegration() {
  return {
    name: '@matthewp/meu-adaptador',
    hooks: {
      'astro:config:done': ({ setAdapter }) => {
        setAdapter({
          name: '@matthewp/meu-adaptador',
          serverEntrypoint: '@matthewp/meu-adaptador/server.js',
          adapterFeatures: {
              functionPerRoute: true
          } 
        });
      },

      'astro:build:ssr': ({ entryPoints }) => {
          for (const [route, entryFile] of entryPoints) {
              // faça algo com a route e entryFile
          }
      }  
    },
  };
}
```

:::caution
O `entryFile` é do tipo `URL` e representa o caminho físico do arquivo no sistema de arquivos. Isso significa que os caminhos mudam com base no SO onde o código é executado. 
:::

#### Ambientes Serverless

Definir `functionPerRoute: true` em um ambiente serverless cria um arquivo JavaScript (handler) para cada rota. Um handler pode terr nomes diferentes com base na sua plataforma de hospedagem: lambda, function, page, etc. 

Cada uma dessas rotas é sujeita a um [cold start](https://azure.microsoft.com/en-us/blog/understanding-serverless-cold-start/) quando o handler é executado, o que pode causar algum delay. Esse delay é influenciado por diferentes fatores.

Com `functionPerRoute: false`, há apenas um único handler no comando da renderização de todas as suas rotas. Quando esse handler é ativado pela primeira vez, você estará sujeito a um cold start. E então, todas as outras rotas devem funcionar sem delay. Porém, você irá perder o benefício da separação de código que `functionPerRoute: true` fornece.

:::note
É importante que você entenda sua plataforma de hospedagem, e como ela funciona, para que você escolha a configuração de `functionPerRoute` apropriada para seu projeto.
:::

### `edgeMiddleware`

Define se algum código de middleware SSR passará por bundle ao ser construído.

Quando habilitado, isso previne código de middleware de passar por bundle e ser importado por todas as páginas durante a build:

```js title="meu-adaptador.mjs" ins={9-11}
export default function createIntegration() {
  return {
    name: '@matthewp/meu-adaptador',
    hooks: {
      'astro:config:done': ({ setAdapter }) => {
        setAdapter({
          name: '@matthewp/meu-adaptador',
          serverEntrypoint: '@matthewp/meu-adaptador/server.js',
          adapterFeatures: {
              edgeMiddleware: true
          } 
        });
      },
    },
  };
}
```

Então, consuma o hook [`astro:build:ssr`](/pt-br/reference/integrations-reference/#astrobuildssr), que irá te dar um `middlewareEntryPoint`, uma `URL` para o arquivo físico no sistema de arquivos.

```js title="meu-adaptador.mjs" ins={15-19}
export default function createIntegration() {
  return {
    name: '@matthewp/meu-adaptador',
    hooks: {
      'astro:config:done': ({ setAdapter }) => {
        setAdapter({
          name: '@matthewp/meu-adaptador',
          serverEntrypoint: '@matthewp/meu-adaptador/server.js',
          adapterFeatures: {
              edgeMiddleware: true
          } 
        });
      },

      'astro:build:ssr': ({ middlewareEntryPoint }) => {
          // lembre-se de verificar se essa propriedade existe, ela será `undefined` se o adaptador não optar pela funcionalidade
          if (middlewareEntryPoint) {
             createEdgeMiddleware(middlewareEntryPoint)
          }
      }  
    },
  };
}

function createEdgeMiddleware(middlewareEntryPoint) {
    // emite um novo arquivo físico utilizando seu bundler
}
```
